<?php
#
# dmBridge: a data access framework for CONTENTdm(R)
#
# Copyright © 2009, 2010, 2011 Board of Regents of the Nevada System of Higher
# Education, on behalf of the University of Nevada, Las Vegas
#

/**
 * Encapsulates an HTTP request. The incoming request is accessible via
 * getCurrent(). Outgoing requests can be created manually and sent using
 * DMHTTPClient.
 *
 * @author Alex Dolski <alex.dolski@unlv.edu>
 * @license http://www.opensource.org/licenses/mit-license.php
 */
final class DMHTTPRequest extends DMHTTPMessage {

	/** @var DMHTTPRequest */
	private static $current;
	/** @var DMHTTPMethod */
	private $method;
	/** @var string */
	private $password;
	/** @var DMURI */
	private $redirected_uri;
	/** @var DMSession */
	private $session;
	/** @var DMURI */
	private $uri;
	/** @var string */
	private $username;


	/**
	 * @return DMHTTPRequest
	 */
	public static function getCurrent() {
		if (!self::$current) {
			// build the incoming DMHTTPRequest
			$method = DMHTTPMethod::GET;
			if (array_key_exists("REQUEST_METHOD", $_SERVER)) {
				switch ($_SERVER['REQUEST_METHOD']) {
				case "POST":
					$method = DMHTTPMethod::POST;
					break;
				}
			}
			
			$uri = self::getHostURI() . $_SERVER['REQUEST_URI'];
			$uri = new DMInternalURI($uri);
			self::$current =  new DMHTTPRequest($uri, $method);
			self::unMagicQuotes($_POST);

			// set representation
			$rep = new DMHTTPRepresentation();
			self::$current->setRepresentation($rep);
			// set form data
			foreach ($_POST as $key => $value) {
				$rep->addFormData($key, $value);
			}
			// set session
			self::$current->setSession(new DMSession());

			// not using these anymore; let the GC eat them
			unset($_GET);
			unset($_POST);
		}
		return self::$current;
	}

	/**
	 * @return string The absolute URI of the web server.
	 */
	private static function getHostURI() {
		$http = "";
		if (array_key_exists("HTTPS", $_SERVER)) {
			$http = ($_SERVER['HTTPS'] && $_SERVER['HTTPS'] != "off") ? "s" : "";
		}
		$tmp = explode("/", $_SERVER['SERVER_PROTOCOL']);
		$protocol = strtolower($tmp[0]) . $http;
		$port = ($_SERVER['SERVER_PORT'] == 80)
			? "" : ":" . $_SERVER['SERVER_PORT'];
		return $protocol . "://" . $_SERVER['SERVER_NAME'] . $port;
	}

	/**
	 * Redirects to a given set of URI params. Must be called before the HTTP
	 * header has been output.
	 *
	 * @param string params
	 * @param array query Optional array of key => value query string pairs
	 * @since 0.1
	 */
	public static function redirectToParams(
			$params, array $query = array()) {
		$uri = self::getCurrent()->getURI();
		$uri->setParams($params);
		if (!count($query)) {
			$uri->unsetQuery();
		}
		foreach ($query as $key => $value) {
			$uri->addQueryValue($key, $value);
		}

		self::redirectToURI(new DMURI($uri->getAbsoluteURIAsString()));
	}

	/**
	 * Redirects to a given URI via a HTTP 302 redirect header. Must be called
	 * before the HTTP header has been output.
	 *
	 * @param DMURI uri
	 * @since 2.0
	 */
	public static function redirectToURI(DMURI $uri) {
		header("Location: " . $uri);
	}

	/**
	 * "Redirects" to the current URI via a HTTP 302 redirect header. Must be
	 * called before the HTTP header has been output.
	 */
	public static function reload() {
		self::redirectToURI(self::getCurrent()->getURI());
	}

	/**
	 * Reverses the effect of PHP magic quotes, if enabled, by running
	 * stripslashes() on $array_or_string. Modifies it by reference and returns
	 * void.
	 *
	 * @param array_or_string
	 * @return void
	 */
	private static function unMagicQuotes(&$array_or_string) {
		if (get_magic_quotes_gpc()) {
			if (is_array($array_or_string)) {
				foreach ($array_or_string as &$value) {
					if (!is_array($value)) {
						$value = stripslashes($value);
					} else {
						self::unMagicQuotes($value);
					}
				}
			}
		}
	}

	/**
	 * @param DMURI uri
	 * @param int method One of the DMHTTPMethod constants
	 */
	public function __construct(DMURI $uri = null,
			$method = DMHTTPMethod::GET) {
		$this->setRepresentation(new DMHTTPRepresentation());
		if (!is_null($method)) {
			$this->setMethod($method);
		}
		if (!is_null($uri)) {
			$this->setURI($uri);
		}
	}

	/**
	 * @return int One of the DMHTTPMethod constants
	 */
	public function getMethod() {
		return $this->method;
	}

	/**
	 * @param int method One of the DMHTTPMethod constants
	 */
	public function setMethod($method) {
		$this->method = $method;
	}

	/**
	 * @return string The password to supply for HTTP authentication.
	 */
	public function getPassword() {
		return $this->password;
	}

	/**
	 * @param string password The password to supply for HTTP authentication.
	 */
	public function setPassword($password) {
		$this->password = $password;
	}

	/**
	 * @return DMURI Clone of the URI to which the request was ultimately
	 * redirected. If the request was not redirected, returns null.
	 * @see getURI()
	 */
	public function getRedirectedURI() {
		return $this->redirected_uri ? clone $this->redirected_uri : null;
	}

	/**
	 * @param DMURI uri The URI to which the request was ultimately redirected.
	 * @see setURI()
	 */
	public function setRedirectedURI(DMURI $uri) {
		$this->redirected_uri = $uri;
	}

	/**
	 * @return DMSession The session associated with the request. This applies
	 * only to incoming requests.
	 */
	public function getSession() {
		return $this->session;
	}

	/**
	 * @param DMSession session The session associated with the request. This
	 * applies only to incoming requests.
	 */
	public function setSession(DMSession $session) {
		$this->session = $session;
	}

	/**
	 * @return DMURI A clone of the request's URI
	 * @see getRedirectedURI()
	 */
	public function getURI() {
		return clone $this->uri;
	}

	/**
	 * @param DMURI uri
	 * @see setRedirectedURI()
	 */
	public function setURI(DMURI $uri) {
		$this->uri = $uri;
	}

	/**
	 * @return string
	 */
	public function getUsername() {
		return $this->username;
	}

	/**
	 * @param string username 
	 */
	public function setUsername($username) {
		$this->username = $username;
	}

}
